package cn.jtfadmin.core.modules.range;

import cn.jtfadmin.base.data.jpa.range.JpaDataRangeRule;
import cn.jtfadmin.base.lang.common.domain.dto.AntdvTreeDataRDTO;
import cn.jtfadmin.base.lang.common.security.UserDetails;
import cn.jtfadmin.base.lang.common.service.BaseTreeService;
import cn.jtfadmin.base.lang.config.ApplicationHolder;
import cn.jtfadmin.base.lang.config.user.UserHolder;
import cn.jtfadmin.core.config.shiro.UserDetailsPropertiesKey;
import cn.jtfadmin.core.constant.OrgTypeConstant;
import cn.jtfadmin.core.modules.sys.domain.entity.SysDepartEntity;
import cn.jtfadmin.core.modules.sys.domain.entity.SysRoleEntity;
import cn.jtfadmin.core.modules.sys.domain.entity.SysUserEntity;
import cn.jtfadmin.core.modules.sys.service.SysDepartActionService;
import cn.jtfadmin.core.modules.sys.utils.SysUserDetailUtil;
import org.apache.shiro.authc.UnknownAccountException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;

/**
 * 部门数据范围
 */
@Component
public class DepartRangeRule implements JpaDataRangeRule {

    /**
     * 本机构及以下
     */
    private String thisOrgAndChildren = "1";

    /**
     * 本机构
     */
    private String thisOrg = "2";

    /**
     * 本部门及一下
     */
    private String thisDepAndChildren = "3";

    /**
     * 本部门
     */
    private String thisDep = "4";

    /**
     * 自定义机构
     */
    private String customerOrg = "5";

    @Autowired
    private BaseTreeService<SysDepartEntity> sysDepartEntityBaseTreeService;

    @Autowired
    private SysDepartActionService sysDepartActionService;

//    @Autowired
//    private SysDataUpdateAspect sysDataUpdateAspect;

    @Autowired
    private ObjectProvider<DepartRange> departRangeObjectProvider;

    @Override
    public String getName() {
        return "sysDepart";
    }

    @Override
    public String getDisplayName() {
        return "机构数据范围";
    }


    @Override
    public List<AntdvTreeDataRDTO> getAntdTreeDataRDTO() {
        UserDetails userDetails = UserHolder.getUserDetails();
        if (Objects.isNull(userDetails)) {
            throw new UnknownAccountException("用户未登录");
        }

        List<AntdvTreeDataRDTO> antdvTreeDataRDTOS = sysDepartEntityBaseTreeService.findAntdTree("name");
        return Arrays.asList(
                new AntdvTreeDataRDTO("本机构及下级机构", thisOrgAndChildren, null),
                new AntdvTreeDataRDTO("本机构", thisOrg, null),
                new AntdvTreeDataRDTO("本部门及下级机构", thisDepAndChildren, null),
                new AntdvTreeDataRDTO("本部门", thisDep, null),
                new AntdvTreeDataRDTO("自定义机构", customerOrg, antdvTreeDataRDTOS)
        );
    }



    @Override
    public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder criteriaBuilder) {
        UserDetails userDetails = UserHolder.getUserDetails();
        if (Objects.isNull(userDetails)) {
            return null;
        }
        // 非系统用户不过滤
        if (!UserDetailsPropertiesKey.TYPE.equals(userDetails.getType())) {
            return null;
        }

        Set<String> managerDepIds = SysUserDetailUtil.getManagerDepIds(userDetails);
        Class<?> javaType = root.getJavaType();
        CriteriaBuilder.In<Object> in = null;
        if (javaType == SysUserEntity.class) {
            in = criteriaBuilder.in(root.get("sysDepart").get("id"));
        } else if (javaType == SysRoleEntity.class) {
            in = criteriaBuilder.in(root.get("sysDepart").get("id"));
        } else if (javaType == SysDepartEntity.class) {
            in = criteriaBuilder.in(root.get("id"));
        };
        if(in == null){
            Iterator<DepartRange> iterator = departRangeObjectProvider.iterator();
            while (in == null && iterator.hasNext()){
                DepartRange next = iterator.next();
                in = next.toPredicateIn(javaType, root, query, criteriaBuilder);
            }
        }
        if (Objects.nonNull(in)) {
            for (String managerDepId : managerDepIds) {
                in.value(managerDepId);
            }
        }
        query.distinct(true);
        return in;
    }


    /**
     * 获取子机构id， 不通用，需要绕过权限
     * @param id
     * @return
     */
    private List<String> findDepChildrenIds(String id) {
        ApplicationContext applicationContext = ApplicationHolder.getApplicationContext();
        EntityManager bean = applicationContext.getBean(EntityManager.class);
        CriteriaBuilder criteriaBuilder = bean.getCriteriaBuilder();
        CriteriaQuery<String> query = criteriaBuilder.createQuery(String.class);
        Root<SysDepartEntity> from = query.from(SysDepartEntity.class);
        query.where(criteriaBuilder.like(from.get("parentIds"), "%," + id + ",%"));
        query.select(from.get("id"));
        return bean.createQuery(query).getResultList();
    }

    public Set<String> parseKeys(Set<String> dataRangeKeys, SysUserEntity sysUserEntity) {
        Set<String> result = new HashSet<>();
        if (dataRangeKeys.contains(thisOrgAndChildren)) {
            SysDepartEntity sysDepart = sysUserEntity.getSysDepart();
            if (Objects.nonNull(sysDepart)) {
                SysDepartEntity company = sysDepartActionService.findParentForType(sysDepart, OrgTypeConstant.ORG_TYPE_COMPANY);
                result.addAll(findDepChildrenIds(company.getId()));
                result.add(company.getId());
            }
        }

        if (dataRangeKeys.contains(thisOrg)) {
            SysDepartEntity sysDepart = sysUserEntity.getSysDepart();
            if (Objects.nonNull(sysDepart)) {
                result.add(sysDepart.getId());
            }
        }

        if (dataRangeKeys.contains(thisDepAndChildren)) {
            SysDepartEntity sysDepart = sysUserEntity.getSysDepart();
            if (Objects.nonNull(sysDepart)) {
                result.addAll(findDepChildrenIds(sysDepart.getId()));
                result.add(sysDepart.getId());
            }
        }

        if (dataRangeKeys.contains(thisDep)) {
            SysDepartEntity sysDepart = sysUserEntity.getSysDepart();
            if (Objects.nonNull(sysDepart)) {
                result.add(sysDepart.getId());
            }
        }
        result.addAll(dataRangeKeys);
        result.remove(thisOrgAndChildren);
        result.remove(thisOrg);
        result.remove(thisDepAndChildren);
        result.remove(thisDep);
        result.remove(customerOrg);
        return result;

    }
}
